/**
 * 通用js方法封装处理
 * Copyright (c) 2019 ruoyi
 */





/**
 * 将毫秒，转换成时间字符串。例如说，xx 分钟
 *
 * @param ms 毫秒
 * @returns {string} 字符串
 */
export function formatCostTime(ms: number): string {
  const day = Math.floor(ms / (24 * 60 * 60 * 1000))
  const hour = Math.floor(ms / (60 * 60 * 1000) - day * 24)
  const minute = Math.floor(ms / (60 * 1000) - day * 24 * 60 - hour * 60)
  const second = Math.floor(ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60)
  if (day > 0) {
    return day + ' 天' + hour + ' 小时 ' + minute + ' 分钟'
  }
  if (hour > 0) {
    return hour + ' 小时 ' + minute + ' 分钟'
  }
  if (minute > 0) {
    return minute + ' 分钟'
  }
  if (second > 0) {
    return second + ' 秒'
  } else {
    return 0 + ' 秒'
  }
}







// 日期格式化
export function parseTime(time:any, pattern:string) {
  if (arguments.length === 0 || !time) {
    return ''
  }
  const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' //默认格式为{y}-{m}-{d} {h}:{i}:{s}（对应yyyy-MM-dd HH:mm:ss）。
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {//如果是纯数字字符串，转为数字（处理时间戳字符串）
      time = parseInt(time)
    } else if (typeof time === 'string') {//如果是其他字符串，替换-为/（解决Safari兼容），去掉T和毫秒部分（ISO格式处理）
      time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '')
    }
    if ((typeof time === 'number') && (time.toString().length === 10)) {//如果是10位数字时间戳（秒级），乘以1000转为毫秒级
      time = time * 1000
    }
    date = new Date(time)
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  type FormatKey = 'y' | 'm' | 'd' | 'h' | 'i' | 's' | 'a';
  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { //有 /g 的情况​替换所有匹配结果
    const formatKey = key as FormatKey;
    let value = formatObj[formatKey]
    // Note: getDay() returns 0 on Sunday
    if (formatKey === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
    if (result.length > 0 && value < 10) {
      value = '0' + value
    }
    return value || 0
  })
  return time_str
}

// 表单重置
export function resetForm(refName:string) {
  if (this.$refs[refName]) {
    this.$refs[refName].resetFields()
  }

}

// 添加日期范围
export function addDateRange(params:any, dateRange:any[], propName:string) {
  let search = params
  search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {}
  dateRange = Array.isArray(dateRange) ? dateRange : []
  if (typeof (propName) === 'undefined') {
    search.params['beginTime'] = dateRange[0]
    search.params['endTime'] = dateRange[1]
  } else {
    search.params['begin' + propName] = dateRange[0]
    search.params['end' + propName] = dateRange[1]
  }
  return search
}

/** 回显数据字典，datas是一个对象例如
        "sys_normal_disable": [
            {
                "label": "正常",
                "value": "0",
                "elTagType": "primary",
                "elTagClass": null
            },
            {
                "label": "停用",
                "value": "1",
                "elTagType": "danger",
                "elTagClass": null
            }
        ]
    ,value就是这个数组里面对应的value
*/
export function selectDictLabel(datas: any[], value: string | number | undefined): string{
  if (value === undefined) {
    return "";
  }
  // 将value转为字符串，因为比较时使用 == ('' + value)
  const valueStr = String(value);
  // 使用数组的find方法查找
  const item = datas.find(item => String(item.value) === valueStr);
  // 如果找到，返回label，否则返回传入的value的字符串形式
  return item ? item.label : valueStr;
}

// some() 方法用于检测数组中是否至少有一个元素满足指定条件。它会遍历数组，并对每个元素执行提供的测试函数，直到找到一个使得测试函数返回真值（truthy）的元素。
// 如果找到这样的元素，some() 会立即返回 true，不再继续遍历剩余元素。如果遍历完所有元素都没有找到符合条件的元素，则返回 false。
// 回显数据字典（字符串、数组）
export function selectDictLabels(
  datas: any[],
  value: string | number | any[] | undefined,
  separator: string = ","
): string {
  // 空值处理
  if (value == null || value === '') return "";
  
  // 统一转换为字符串数组
  const valueArray = Array.isArray(value) 
    ? value.map(String)
    : String(value).split(separator);
  
  // 创建快速查找表（仅使用 value 和 label）
  const lookupMap = new Map();
  for (const item of datas) {
    // 检查是否有必要属性
    if (item && item.value != null && item.label != null) {
      // 使用字符串作为键避免类型问题
      const key = String(item.value);
      // 只保存第一次出现的值（避免重复）
      if (!lookupMap.has(key)) {
        lookupMap.set(key, item.label);
      }
    }
  }
  
  // 构建结果数组
  const result = valueArray.map(val => 
    lookupMap.has(val) ? lookupMap.get(val) : val
  );
  
  return result.join(separator);
}

// 字符串格式化(%s )
export function sprintf(str:string) {
  var args = arguments, flag = true, i = 1
  str = str.replace(/%s/g, function () {
    var arg = args[i++]
    if (typeof arg === 'undefined') {
      flag = false
      return ''
    }
    return arg
  })
  return flag ? str : ''
}


export const defaultProps = {
  children: 'children',
  label: 'label',
  value: 'id',
  isLeaf: 'leaf',
  emitPath: false // 用于 cascader 组件：在选中节点改变时，是否返回由该节点所在的各级菜单的值所组成的数组，若设置 false，则只返回该节点的值
}


export const generateUUID = () => {
  if (typeof crypto === 'object') {
    if (typeof crypto.randomUUID === 'function') {
      return crypto.randomUUID()
    }
    if (typeof crypto.getRandomValues === 'function' && typeof Uint8Array === 'function') {
      const callback = (c: any) => {
        const num = Number(c)
        return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString(
          16
        )
      }
      return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, callback)
    }
  }
  let timestamp = new Date().getTime()
  let performanceNow =
    (typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    let random = Math.random() * 16
    if (timestamp > 0) {
      random = (timestamp + random) % 16 | 0
      timestamp = Math.floor(timestamp / 16)
    } else {
      random = (performanceNow + random) % 16 | 0
      performanceNow = Math.floor(performanceNow / 16)
    }
    return (c === 'x' ? random : (random & 0x3) | 0x8).toString(16)
  })
}


// 转换字符串，undefined,null等转化为""
export function parseStrEmpty(str:any) {
  if (!str || str == "undefined" || str == "null") {
    return ""
  }
  return str
}

// 数据合并
export function mergeRecursive(source:any, target:any) {
  for (var p in target) {
    try {
      if (target[p].constructor == Object) {
        source[p] = mergeRecursive(source[p], target[p])
      } else {
        source[p] = target[p]
      }
    } catch (e) {
      source[p] = target[p]
    }
  }
  return source
}


// 通用的树节点接口
interface TreeNode {
  [key: string]: any;
}

// 方案1: 完全自动推断类型的 handleTree
export function handleTree<T = any>(
  data: T[], 
  id?: string, 
  parentId?: string, 
  children?: string
): T[] {
  const config = {
    id: id || 'id',
    parentId: parentId || 'parentId',
    childrenList: children || 'children'
  };

  const childrenListMap: { [key: string]: T } = {};
  const tree: T[] = [];

  // 第一遍遍历：建立映射关系并初始化 children
  for (const item of data) {
    const itemId = (item as any)[config.id];
    if (itemId !== undefined && itemId !== null) {
      childrenListMap[itemId.toString()] = item;
    }
    
    // 确保每个节点都有 children 数组
    if (!(item as any)[config.childrenList]) {
      (item as any)[config.childrenList] = [];
    }
  }

  // 第二遍遍历：构建树结构
  for (const item of data) {
    const itemParentId = (item as any)[config.parentId];
    
    if (itemParentId !== undefined && itemParentId !== null) {
      const parentObj = childrenListMap[itemParentId.toString()];
      if (parentObj) {
        ((parentObj as any)[config.childrenList] as T[]).push(item);
      } else {
        tree.push(item);
      }
    } else {
      tree.push(item);
    }
  }

  return tree;
}





/**
* 参数处理
* @param {*} params  参数
*/
export function tansParams(params:any) {
  let result = ''
  for (const propName of Object.keys(params)) {
    const value = params[propName]
    var part = encodeURIComponent(propName) + "="
    if (value !== null && value !== "" && typeof (value) !== "undefined") {
      if (typeof value === 'object') {
        for (const key of Object.keys(value)) {
          if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
            let params = propName + '[' + key + ']'
            var subPart = encodeURIComponent(params) + "="
            result += subPart + encodeURIComponent(value[key]) + "&"
          }
        }
      } else {
        result += part + encodeURIComponent(value) + "&"
      }
    }
  }
  return result
}

// 返回项目路径
export function getNormalPathBackup(p: string) {
  if (p.length === 0 || !p || p == 'undefined') {
    return p
  }
  let res = p.replace('//', '/')
  if (res[res.length - 1] === '/') {
    return res.slice(0, res.length - 1)
  }
  return res
}


/**
 * 规范化路径（处理双斜杠和末尾斜杠）
 * @param p 原始路径
 * @returns 规范化后的路径
 */
export function getNormalPath(p: string): string {
  // 处理异常输入
  if (!p || p.length === 0 || p === 'undefined') {
    return p;
  }

  // 替换连续的双斜杠为单斜杠
  // 注意：正则表达式 /\/+/g 替换所有连续斜杠（比 replace('//', '/') 更健壮）
  let normalized = p.replace(/\/+/g, '/');
  
  // 处理开头连续斜杠的特殊情况
  if (normalized.startsWith('//')) {
    normalized = normalized.slice(1);
  }
  
  // 移除末尾的斜杠（除非整个路径就是根路径 '/'）
  if (normalized !== '/' && normalized.endsWith('/')) {
    normalized = normalized.slice(0, -1);
  }
  
  return normalized;
}

// 验证是否为blob格式
export function blobValidate(data: any): boolean {
  // 首先检查是否为Blob实例
  if (data instanceof Blob) {
    // 额外检查：排除JSON类型（可选，根据实际需求）
    return data.type !== 'application/json';
  }
  return false;
}